/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - geometry/mesh
// Copyright( c) 2015.  All Rights Reserved
//
// File:		AEMeshBuffer.cpp
// Author:		Gianluca Belardelli
// Date:		11/02/2015
//
/////////////////////////////////////////////////////////////////////////
#include <AEEngine.h>

extern AEUINT32 platform2PrimitiveTypeConvert( AEPrimitiveType ePrimType );

AEMeshBuffer::AEMeshBuffer( void ) : AEResource( AENULL ), m_ePrimType( AEPRIMITIVETYPE_TRILIST )
{
}

AEMeshBuffer::AEMeshBuffer( const AEVertexDescriptor &vdDescr, AEINT32 nVertexCount, 
							AEPrimitiveType ePrimType, 
							AEINT32 nIndexCount, AEINT32 nPrimCount, 
							AEINT32 nUsageFlag, 
							AEBOOL32 bDoubleBufferedVertices, 
							AEBOOL32 bDoubleBufferedIndices ) : AEResource( AENULL ),
								m_ePrimType( ePrimType ),
								m_nAllocVertexCount( nVertexCount ),
								m_nAllocIndexCount( nIndexCount ),
								m_nCurrentPrimCount( nPrimCount ),
								m_bVerticesDoubleBuffered( bDoubleBufferedVertices ),
								m_bIndicesDoubleBuffered( bDoubleBufferedIndices ),
								m_vdVertexDescr( vdDescr )
{
	if( m_nCurrentPrimCount < 0 )
	{
		if( m_ePrimType == AEPRIMITIVETYPE_INDEXED_TRILIST )
			m_nCurrentPrimCount = nVertexCount / 3;
	}

	m_ePrimType = platform2PrimitiveTypeConvert( (AEPrimitiveType)m_ePrimType );

	if( m_nAllocVertexCount > 0 )
		AllocateVertices( m_vdVertexDescr, m_nAllocVertexCount, nUsageFlag, m_bVerticesDoubleBuffered );

	if( m_nAllocIndexCount > 0 )
		AllocateIndexList( m_nAllocIndexCount, nUsageFlag, AEINDEXFORMAT_16, m_bIndicesDoubleBuffered );
}

AEMeshBuffer::~AEMeshBuffer( void )
{
	for( AEINT32 i=0; i<AEMAX_MESHBUFFER_TEXCOORDS; i++ )
	{
		if( m_lpChannelTex[i] )
			m_lpChannelTex[i]->Release();
	}
}
	
void AEMeshBuffer::FreeVertices( void )
{
	m_spVertexBuffer->Release();
}
	
void AEMeshBuffer::FreeIndexList( void )
{
}

AEBOOL32 AEMeshBuffer::SetPrimitiveCount( AEINT32 nNewCount )
{
	m_nCurrentPrimCount = nNewCount;
	return AETRUE;
}

AEINT32 AEMeshBuffer::GetCurrentPrimitiveCount( void ) const
{
	return m_nCurrentPrimCount;
}

void *AEMeshBuffer::LockVertices( AEINT32 nFlags, AEINT32 nFirst, AEINT32 nCount )
{
	if( m_spVertexBuffer )
		return m_spVertexBuffer->Lock( nFlags, nFirst, m_vdVertexDescr.m_sStride * m_nAllocVertexCount );

	return AENULL;
}
	
void AEMeshBuffer::UnLockVertices( void )
{
	if( m_spVertexBuffer->IsLocked() )
		m_spVertexBuffer->Unlock();
}
	
void *AEMeshBuffer::LockIndices( AEINT32 nFlags, AEINT32 nFirst, AEINT32 nCount )
{
	if( m_spIndexBuffer )
		return m_spIndexBuffer->Lock( nFlags, nFirst, nCount );

	return AENULL;
}
	
void AEMeshBuffer::UnLockIndices( void )
{
	if( m_spIndexBuffer->IsLocked() )
		m_spIndexBuffer->Unlock();
}

void AEMeshBuffer::FillVerticesWithData( const void *lpSourceData, AEINT32 nMemSize, AEBOOL32 bNoOverwrite )
{
	if( m_spVertexBuffer )
	{
		void *lpPtr = m_spVertexBuffer->Lock( AELOCKFLAG_REPLACE_ALL, 0, nMemSize );
		memcpy( lpPtr, lpSourceData, nMemSize );
		m_spVertexBuffer->Unlock();
	}
}

void AEMeshBuffer::FillIndicesWithData( const void *lpSourceData, AEINT32 nMemSize, AEBOOL32 bNoOverwrite )
{
	if( m_spIndexBuffer )
	{
		void *lpPtr = m_spIndexBuffer->Lock( AELOCKFLAG_REPLACE_ALL, 0, nMemSize );
		memcpy( lpPtr, lpSourceData, nMemSize );
		m_spIndexBuffer->Unlock();
	}
}

AETexture *AEMeshBuffer::SetBaseTexture( const char *lpFilename )
{
	return AENULL;
}

AETexture *AEMeshBuffer::SetChannelTexture( const char *lpFilename, AEINT32 nChannel )
{
	return AENULL;
}

void AEMeshBuffer::SetVertexBuffer( AEVertexBuffer *lpVertexBuffer, const AEVertexDescriptor &vdDescr, AEINT32 nCount, AEINT32 nUsageFlag, AEINT32 nAdditionalBindFlag )
{
	if( m_spVertexBuffer )
	{
		m_spVertexBuffer->Release();
		m_spVertexBuffer = lpVertexBuffer;
	}
}

void AEMeshBuffer::SetIndexBuffer( AEIndexBuffer *lpIndexBuffer, AEINT32 nIndexCount, AEINT32 nUsageFlag, AEINT32 nAdditionalBindFlag )
{
	if( m_spIndexBuffer )
	{
		m_spIndexBuffer->Release();
		m_spIndexBuffer = lpIndexBuffer;
	}
}

AEIndexFormat AEMeshBuffer::GetIndexType( void ) const
{
	return AEINDEXFORMAT_16;
}

AEMeshBuffer *AEMeshBuffer::FlattenOutIndexBuffer( void )
{
	return AENULL;
}

AEINT32 AEMeshBuffer::GetCalcPrimitiveCount( AEPrimitiveType eType, AEINT32 nVertexCount, AEINT32 nIndexCount )
{
	///   \li per AEPRIMITIVETYPE_TRILIST:  max count = numVertices / 3,
	///   \li per AEPRIMITIVETYPE_TRISTRIP: max count = numVertices - 2,
	///   \li per AEPRIMITIVETYPE_INDEXED_TRILIST:  max count = numIndices / 3,
	///   \li per AEPRIMITIVETYPE_INDEXED_TRISTRIP: max count = numIndices - 2,
	///   \li per AEPRIMITIVETYPE_LINELIST: max count = numVertices / 2
	///   \li per AEPRIMITIVETYPE_INDEXED_LINELIST: max count = numIndices / 2
	///   \li per AEPRIMITIVETYPE_POINTLIST: max count = numVertices
	AEINT32 nRes = -1;

	switch( eType )
	{
		case AEPRIMITIVETYPE_TRILIST:
			if( nVertexCount > 2 ) 
				nRes = nVertexCount / 3; 
			break;
		case AEPRIMITIVETYPE_TRISTRIP:
			if( nVertexCount > 1 ) 
				nRes = nVertexCount - 2; 
			break;
		case AEPRIMITIVETYPE_INDEXED_TRILIST:
			if( nIndexCount > 2 ) 
				nRes = nIndexCount / 3; 
			break;
		case AEPRIMITIVETYPE_INDEXED_TRISTRIP:
			if( nIndexCount > 1 ) 
				nRes = nIndexCount - 2; 
			break;
		case AEPRIMITIVETYPE_LINELIST:
			if( nVertexCount > 1 ) 
				nRes = nVertexCount / 2; 
			break;
		case AEPRIMITIVETYPE_INDEXED_LINELIST:
			if( nIndexCount > 1 ) 
				nRes = nIndexCount / 2; 
			break;
		case AEPRIMITIVETYPE_POINTLIST:
			if( nVertexCount > 0 ) 
				nRes = nVertexCount; 
			break;
		default:
			nRes = -1;
	};

	return nRes;
}

AEBOOL32 AEMeshBuffer::Reload( void )
{
	return AETRUE;
}

AEBOOL32 AEMeshBuffer::Unload( void )
{
	return AETRUE;
}

void AEMeshBuffer::AccumulateMemoryFootprint(size_t &iUniqueSys, size_t &iUniqueGPU, size_t &iDependentSys, size_t &iDependentGPU)
{

}

void AEMeshBuffer::RenderBuffer( AEMatrix4f &matWorld, AEUINT32 nStart, AEUINT32 nEnd )
{
	//AEASSERT( m_spVertexBuffer->GetSize() == 0 );
	//platformRender( matWorld, nStart, nEnd );
}

void AEMeshBuffer::RenderBuffer( AEUINT32 nStart, AEUINT32 nEnd )
{
	//AEASSERT( m_spVertexBuffer->GetSize() == 0 );
	platformRender( nStart, nEnd );
}

